package com.uvstu.web.controller.common;

import com.alibaba.fastjson2.JSONObject;
import com.uvstu.common.config.RuoYiConfig;
import com.uvstu.common.core.domain.entity.SysUser;
import com.uvstu.common.upay.Result;
import com.uvstu.system.domain.SApplication;
import com.uvstu.system.domain.SPayConfig;
import com.uvstu.system.domain.SUorder;
import com.uvstu.system.service.*;
import com.uvstu.common.exception.TClientException;
import com.uvstu.common.upay.EncryptionUtil;
import com.uvstu.common.utils.HttpsUtil;
import com.uvstu.common.upay.pay.AliPayUtil;
import com.uvstu.common.upay.pay.WxPayUtil;
import com.uvstu.common.upay.pay.config.AliPayConfigUtil;
import com.uvstu.common.upay.pay.config.WxPayConfigUtil;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 对外开放支付接口 openApiController
 *
 * @author zwb
 * @date 2023-02-02
 */
@RestController
@RequestMapping("/open/api")
public class OpenApiController {

    @Autowired
    private ISApplicationService applicationService;

    @Autowired
    private ISUorderService isUorderService;

    @Autowired
    private ISPayConfigService isPayConfigService;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private ISysDictDataService dictDataService;

    @Autowired
    private ISysUserService iSysUserService;

    @Autowired
    private ISysActivationService iSysActivationService;

    /**
     * 参数传递说明：
     * 参数：头部参数，请求参数
     * 头部参数：签名：sign  应用ID：appid  payType：1 支付宝 2 微信
     * 请求参数 根据支付 或 微信 需要的参数进行传参
     */

    /**
     * 会员激活接口
     * @param email
     * @return
     */
    @RequestMapping(value = "/activation")
    public String activation(String email){
        try{
            email = EncryptionUtil.AESdecrypt(email);
            String[] str = email.split("\\|");
            //获取当前时间
            LocalDateTime currentDateTime = LocalDateTime.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-ddHH");
            String formattedDateTime = currentDateTime.format(formatter);
            if(!formattedDateTime.equals(str[1])){
                return "激活失败，邮件已过期";
            }
            SysUser sysUser = iSysUserService.selectUserByEmail(email);
            if(sysUser == null){
                return "激活失败，邮箱不存在";
            }
            sysUser.setStatus("0");
            iSysUserService.updateActivationUser(sysUser);
            return "激活成功！";
        }catch (Exception e){
            e.printStackTrace();
        }
        return "邮箱错误，激活失败！";
    }

    /**
     * 支付接口
     * @param param
     * @param request
     * @return
     * @throws TClientException
     */
    @RequestMapping(value = "/pay", produces = "application/json;charset=utf-8")
    public Result pay(@RequestBody String param, HttpServletRequest request) throws TClientException {
        Result result = new Result();
        try{
            if(!iSysActivationService.checkVerifyKey()){
                throw new TClientException("平台未激活");
            }
            Map<String,Object> headsMap = null;
            SApplication sApplication = null;
            try{
                //获取头部参数
               headsMap = getHeads(request);
                //查询应用
                sApplication = applicationService.selectSApplicationByAppid(String.valueOf(headsMap.get("appid")));
            }catch (Exception e){
                e.printStackTrace();
                throw new TClientException("应用查询失败！");
            }
            if(sApplication == null){
                throw new TClientException("应用不存在！");
            }
            //验证用户状态
            if(!checkUser(sApplication.getUserId())){
                throw new TClientException("账号已经被停用！");
            }
            //验证是否有该支付通道权限
            if(sApplication.getPayMethod() != 3){
                if(!String.valueOf(headsMap.get("type")).equals(String.valueOf(sApplication.getPayMethod()))){
                    throw new TClientException("无该支付通道权限！");
                }
            }
            if(sApplication.getStatus() == 1){
                throw new TClientException("该应用未启用！");
            }
            JSONObject p = JSONObject.parseObject(param);
            boolean checkSign = checkSign(p,sApplication.getSignKey(),String.valueOf(headsMap.get("sign")));
            if(!checkSign){
                throw new TClientException("签名错误！");
            }else{
                //判断交易单号是否重复
                SUorder sUorder = new SUorder();
                sUorder.setAppId(sApplication.getAppId());
                sUorder.setUserId(sApplication.getUserId());
                sUorder.setOutTradeNo(p.getString("outTradeNo"));
                List<SUorder> list = isUorderService.selectSUorderList(sUorder);
                if(list.size() != 0){
                    throw new TClientException("商户交易号重复！");
                }
                if("1".equals(String.valueOf(headsMap.get("type")))){
                    //支付宝
                    //获取支付配置
                    SPayConfig sPayConfig = new SPayConfig();
                    sPayConfig.setPayStatus("2");
                    sPayConfig.setPaymentChannel("1");
                    List<SPayConfig> sPayConfigList = isPayConfigService.selectSPayConfigList(sPayConfig);
                    if(sPayConfigList.size() == 0){
                        throw new TClientException("平台无可用的支付宝通道,请联系管理员");
                    }
                    sPayConfig = sPayConfigList.get(0);
                    String notifyUrl = configService.selectConfigByKey("sys.url") + "/open/pay/api/uAliPayNotify";
                    //封装参数
                    AliPayConfigUtil aliPayConfigUtil = new AliPayConfigUtil(sPayConfig.getGatewayAddress(),sPayConfig.getAppid(),
                            sPayConfig.getKey1(),sPayConfig.getKey2(),dictDataService.selectDictLabel("sign_type",
                            sPayConfig.getSignType()),sPayConfig.getDataFormat(),
                            dictDataService.selectDictLabel("coding_set", sPayConfig.getCodingSet()),notifyUrl,sApplication.getReturnUrl());
                    //订单入库
                    sUorder = new SUorder();
                    try{
                        sUorder.setAppId(sApplication.getAppId());
                        sUorder.setUserId(sApplication.getUserId());
                        sUorder.setOutTradeNo(p.getString("outTradeNo"));
                        sUorder.setGoodName(p.getString("goodName"));
                        sUorder.setPayMethod(1);
                        sUorder.setPrice(p.getBigDecimal("price"));
                        sUorder.setStatus(1);
                        sUorder.setCreateBy("system");
                        sUorder.setCreateTime(new Date());
                        isUorderService.insertSUorder(sUorder);
                    }catch (Exception e){
                        e.printStackTrace();
                        throw new TClientException("订单生成失败，请联系管理员！");
                    }
                    //返回支付内容
                    try{
                        if("1".equals(String.valueOf(headsMap.get("channel")))){
                            AliPayUtil aliPayUtil = new AliPayUtil();
                            String form = aliPayUtil.qrPay(aliPayConfigUtil,sUorder.getOutTradeNo(),String.valueOf(sUorder.getPrice()),
                                    sUorder.getGoodName());
                            result.setData(form);
                        }else if("2".equals(String.valueOf(headsMap.get("channel")))){
                            AliPayUtil aliPayUtil = new AliPayUtil();
                            String form = aliPayUtil.pcPay(aliPayConfigUtil,sUorder.getOutTradeNo(),String.valueOf(sUorder.getPrice()),
                                    sUorder.getGoodName());
                            result.setData(form);
                        }else if("3".equals(String.valueOf(headsMap.get("channel")))){
                            AliPayUtil aliPayUtil = new AliPayUtil();
                            String form = aliPayUtil.wapPay(aliPayConfigUtil,sUorder.getOutTradeNo(),String.valueOf(sUorder.getPrice()),
                                    sUorder.getGoodName());
                            result.setData(form);
                        }
                        return result;
                    }catch (Exception e){
                        result.setError(e.getMessage());
                    }
                }else if("2".equals(String.valueOf(headsMap.get("type")))){
                    //微信
                    //获取支付配置
                    SPayConfig sPayConfig = new SPayConfig();
                    sPayConfig.setPayStatus("2");
                    sPayConfig.setPaymentChannel("2");
                    List<SPayConfig> sPayConfigList = isPayConfigService.selectSPayConfigList(sPayConfig);
                    if(sPayConfigList.size() == 0){
                        throw new TClientException("平台无可用的微信通道,请联系管理员");
                    }
                    sPayConfig = sPayConfigList.get(0);
                    String payNotifyUrl = configService.selectConfigByKey("sys.url") + "/open/pay/api/uWxPayNotify";
                    String refundNotifyUrl = configService.selectConfigByKey("sys.url") + "/open/pay/api/uWxRefundNotify";
                    //封装参数
                    String[] arr = sPayConfig.getCertificatePath().split(",");
                    String certificatePath = "";
                    for (int i = 0; i < arr.length; i++) {
                        if(arr[i].indexOf("p12") != -1){
                            certificatePath = RuoYiConfig.getProfile() + arr[i].replace("/profile/","/");
                        }
                    }
                    WxPayConfigUtil wxPayConfigUtil = new WxPayConfigUtil();
                    wxPayConfigUtil.setConfig(sPayConfig.getAppid(),sPayConfig.getKey2(),sPayConfig.getKey1(),payNotifyUrl,refundNotifyUrl,
                            certificatePath,sPayConfig.getKey1());
                    //订单入库
                    sUorder = new SUorder();
                    try{
                        sUorder.setAppId(sApplication.getAppId());
                        sUorder.setUserId(sApplication.getUserId());
                        sUorder.setOutTradeNo(p.getString("outTradeNo"));
                        sUorder.setGoodName(p.getString("goodName"));
                        sUorder.setPayMethod(2);
                        sUorder.setPrice(p.getBigDecimal("price"));
                        sUorder.setStatus(1);
                        sUorder.setCreateBy("system");
                        sUorder.setCreateTime(new Date());
                        isUorderService.insertSUorder(sUorder);
                    }catch (Exception e){
                        e.printStackTrace();
                        throw new TClientException("订单生成失败，请联系管理员！");
                    }
                    //返回支付内容
                    try{
                        int price = (int)(Double.valueOf(sUorder.getPrice().toString())*100);
                        if("1".equals(String.valueOf(headsMap.get("channel")))){
                            Map<String,String> map = WxPayUtil.pay(wxPayConfigUtil,sUorder.getOutTradeNo(),sUorder.getGoodName(),String.valueOf(price));
                            if(map.get("code_url") != null){
                                result.setData(map.get("code_url"));
                                return result;
                            }
                        }else{
                            throw new TClientException("暂无该支付通道！");
                        }
                    }catch (Exception e){
                        result.setError(e.getMessage());
                    }
                }else{
                    throw new TClientException("暂无该支付类型！");
                }
            }
        }catch (Exception e){
            result.setError(e.getMessage());
        }
        return result;
    }

    /**
     * 订单查询接口
     * @param param
     * @param request
     * @return
     * @throws TClientException
     */
    @RequestMapping(value = "/query", produces = "application/json;charset=utf-8")
    public Result query(@RequestBody String param,HttpServletRequest request) throws TClientException {
        Result result = new Result();
        try{
            if(!iSysActivationService.checkVerifyKey()){
                throw new TClientException("平台未激活");
            }
            Map<String,Object> headsMap = null;
            SApplication sApplication = null;
            try{
                //获取头部参数
                headsMap = getHeads(request);
                //查询应用
                sApplication = applicationService.selectSApplicationByAppid(String.valueOf(headsMap.get("appid")));
            }catch (Exception e){
                e.printStackTrace();
                throw new TClientException("应用查询失败！");
            }
            //验证用户状态
            if(!checkUser(sApplication.getUserId())){
                throw new TClientException("账号已经被停用！");
            }
            if(sApplication == null){
                throw new TClientException("应用不存在！");
            }else{
                if(sApplication.getStatus() == 1){
                    throw new TClientException("该应用未启用！");
                }
                JSONObject p = JSONObject.parseObject(param);
                boolean checkSign = checkSign(p,sApplication.getSignKey(),String.valueOf(headsMap.get("sign")));
                if(!checkSign){
                    throw new TClientException("签名错误！");
                }else{
                    //返回该笔订单即可
                    SUorder sUorder = new SUorder();
                    sUorder.setAppId(sApplication.getAppId());
                    sUorder.setUserId(sApplication.getUserId());
                    sUorder.setOutTradeNo(p.getString("outTradeNo"));
                    sUorder = isUorderService.selectSUorderByOutTradeNo(sUorder);
                    if(sUorder == null){
                        throw new TClientException("未查询到该订单！");
                    }else{
                        JSONObject json = new JSONObject();
                        json.put("appid",sApplication.getAppId());
                        json.put("outTradeNo",sUorder.getOutTradeNo());
                        json.put("tradeNo",sUorder.getTradeNo());
                        json.put("refundNo",sUorder.getRefundNo());
                        json.put("goodName",sUorder.getGoodName());
                        json.put("payMethod",sUorder.getPayMethod());
                        json.put("price",sUorder.getPrice());
                        json.put("transactionTime",sUorder.getTransactionTime());
                        json.put("refundTime",sUorder.getRefundTime());
                        json.put("status",sUorder.getStatus());
                        json.put("createTime",sUorder.getCreateTime());
                        result.setData(json);
                        return result;
                    }
                }
            }
        }catch (Exception e){
            result.setError(e.getMessage());
        }
        return result;
    }

    /**
     * 退款接口
     * @param param
     * @param request
     * @return
     */
    @RequestMapping(value = "/refund", produces = "application/json;charset=utf-8")
    public Result refund(@RequestBody String param,HttpServletRequest request) throws TClientException {
        Result result = new Result();
        try{
            if(!iSysActivationService.checkVerifyKey()){
                throw new TClientException("平台未激活");
            }
            Map<String,Object> headsMap = null;
            SApplication sApplication = null;
            try{
                //获取头部参数
                headsMap = getHeads(request);
                //查询应用
                sApplication = applicationService.selectSApplicationByAppid(String.valueOf(headsMap.get("appid")));
            }catch (Exception e){
                e.printStackTrace();
                throw new TClientException("应用查询失败！");
            }
            //验证用户状态
            if(!checkUser(sApplication.getUserId())){
                throw new TClientException("账号已经被停用！");
            }
            if(sApplication == null){
                throw new TClientException("应用不存在！");
            }
            if(sApplication.getPayMethod() != 3){
                if(!String.valueOf(headsMap.get("type")).equals(String.valueOf(sApplication.getPayMethod()))){
                    throw new TClientException("无该支付通道权限！");
                }
            }
            if(sApplication.getStatus() == 1){
                throw new TClientException("该应用未启用！");
            }
            JSONObject p = JSONObject.parseObject(param);
            boolean checkSign = checkSign(p,sApplication.getSignKey(),String.valueOf(headsMap.get("sign")));
            if(!checkSign){
                throw new TClientException("签名错误！");
            }else{
                SUorder sUorder = new SUorder();
                sUorder.setAppId(sApplication.getAppId());
                sUorder.setUserId(sApplication.getUserId());
                sUorder.setOutTradeNo(p.getString("outTradeNo"));
                sUorder = isUorderService.selectSUorderByOutTradeNo(sUorder);
                if(sUorder == null){
                    throw new TClientException("订单不存在");
                }
                if(sUorder.getStatus() != 2){
                    throw new TClientException("退款失败，订单状态不是支付成功，无法进行退款！");
                }
                if(!isNow(sUorder.getTransactionTime())){
                    throw new TClientException("退款失败，只允许退款单天的订单");
                }
                //判断退款通道
                if("1".equals(String.valueOf(headsMap.get("type")))){
                    //支付宝
                    SPayConfig sPayConfig = new SPayConfig();
                    sPayConfig.setPayStatus("2");
                    sPayConfig.setPaymentChannel("1");
                    List<SPayConfig> sPayConfigList = isPayConfigService.selectSPayConfigList(sPayConfig);
                    if(sPayConfigList.size() == 0){
                        throw new TClientException("平台无可用的支付宝通道,请联系管理员！");
                    }
                    sPayConfig = sPayConfigList.get(0);
                    String notifyUrl = configService.selectConfigByKey("sys.url") + "/open/pay/api/uAliPayNotify";
                    //封装参数
                    try{
                        AliPayConfigUtil aliPayConfigUtil = new AliPayConfigUtil(sPayConfig.getGatewayAddress(),sPayConfig.getAppid(),
                                sPayConfig.getKey1(),sPayConfig.getKey2(),dictDataService.selectDictLabel("sign_type",
                                sPayConfig.getSignType()),sPayConfig.getDataFormat(),
                                dictDataService.selectDictLabel("coding_set", sPayConfig.getCodingSet()),notifyUrl,sApplication.getReturnUrl());
                        BigDecimal price = new BigDecimal(0);
                        if(sUorder.getPrice().compareTo(new BigDecimal(1)) != -1){
                            price = sUorder.getPrice().multiply(new BigDecimal(0.994)).setScale(2, RoundingMode.HALF_UP);
                        }else{
                            price = sUorder.getPrice();
                        }
                        Map<String,Object> map = AliPayUtil.refund(aliPayConfigUtil,sUorder.getOutTradeNo(),sUorder.getTradeNo(),String.valueOf(price),p.getString("refundReason"));
                        if(map.get("alipay_trade_refund_response") != null){
                            String json = JSONObject.parseObject(JSONObject.toJSONString(map.get("alipay_trade_refund_response"))).getString("msg");
                            if("Success".equals(json)){
                                sUorder.setRefundTime(new Date());
                                sUorder.setStatus(5);
                                sUorder.setPayParam(JSONObject.toJSONString(map));
                                isUorderService.updateSUorderResult(sUorder);
                                try{
                                    //通知第三方用户退款结果
                                    JSONObject data = new JSONObject();
                                    data.put("appid",sUorder.getAppId());
                                    data.put("outTradeNo",sUorder.getOutTradeNo());
                                    data.put("tradeNo",sUorder.getTradeNo());
                                    data.put("refundNo",sUorder.getRefundNo());
                                    data.put("goodName",sUorder.getGoodName());
                                    data.put("payMethod",sUorder.getPayMethod());
                                    data.put("price",sUorder.getPrice());
                                    data.put("transactionTime",sUorder.getTransactionTime());
                                    data.put("status",sUorder.getStatus());
                                    data.put("refundTime",sUorder.getRefundTime());
                                    data.put("createTime",sUorder.getCreateTime());
                                    HttpsUtil.doPost(sApplication.getRefundUrl(),JSONObject.toJSONString(data));
                                }catch (Exception e){
                                    System.err.println("退款结果通知失败！");
                                }
                            }
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                        throw new TClientException("第三方请求参数错误！");
                    }
                }else if("2".equals(String.valueOf(headsMap.get("type")))){
                    //微信
                    SPayConfig sPayConfig = new SPayConfig();
                    sPayConfig.setPayStatus("2");
                    sPayConfig.setPaymentChannel("2");
                    List<SPayConfig> sPayConfigList = isPayConfigService.selectSPayConfigList(sPayConfig);
                    if(sPayConfigList.size() == 0){
                        throw new TClientException("平台无可用的微信通道,请联系管理员！");
                    }
                    sPayConfig = sPayConfigList.get(0);
                    String payNotifyUrl = configService.selectConfigByKey("sys.url") + "/open/pay/api/uWxPayNotify";
                    String refundNotifyUrl = configService.selectConfigByKey("sys.url") + "/open/pay/api/uWxRefundNotify";
                    //封装参数
                    try{
                        String[] arr = sPayConfig.getCertificatePath().split(",");
                        String certificatePath = "";
                        for (int i = 0; i < arr.length; i++) {
                            if(arr[i].indexOf("p12") != -1){
                                certificatePath = RuoYiConfig.getProfile() + arr[i].replace("/profile/","/");
                            }
                        }
                        WxPayConfigUtil wxPayConfigUtil = new WxPayConfigUtil();
                        wxPayConfigUtil.setConfig(sPayConfig.getAppid(),sPayConfig.getKey2(),sPayConfig.getKey1(),payNotifyUrl,refundNotifyUrl,
                                certificatePath,sPayConfig.getKey1());
                        int price = (int)(Double.valueOf(sUorder.getPrice().toString())*100);
                        Map<String,String> map = WxPayUtil.refund(wxPayConfigUtil,sUorder.getTradeNo(),sUorder.getOutTradeNo(),String.valueOf(price),String.valueOf(price),p.getString("refundReason"));
                        sUorder.setStatus(4);
                        sUorder.setRefundNo(map.get("refund_id"));
                        isUorderService.updateSUorderResult(sUorder);
                    }catch (Exception e){
                        e.printStackTrace();
                        throw new TClientException("第三方请求参数错误！");
                    }
                }
            }
        }catch (Exception e){
            result.setError(e.getMessage());
        }
        return result;
    }

    /**
     * 校验用户是否被停用
     * @param userId
     * @return
     */
    private boolean checkUser(Long userId){
        SysUser sysUser = iSysUserService.selectUserById(userId);
        if(sysUser != null){
            if("0".equals(sysUser.getStatus())){
                return true;
            }
        }
        return false;
    }

    /**
     * 签名校验
     * @param param
     * @param sginKey
     * @param sgin
     * @return
     */
    private boolean checkSign(JSONObject param,String sginKey,String sgin){
        System.err.println("签名内容："+JSONObject.toJSONString(param));
        String a = sginKey+JSONObject.toJSONString(param)+sginKey;
        try{
            String result = getMd5(a).toLowerCase();
            System.err.println("签名结果："+result);
            if(result.equals(sgin)){
                return true;
            }else{
                return false;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    /**
     * md5字符串加密
     * @param passord
     * @return
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     */
    public static String getMd5(String passord) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        StringBuilder pwd = new StringBuilder("");
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] digest1 = md.digest(passord.getBytes("UTF-8"));
        for (int i = 0; i < digest1.length; i++)
        {
            int v = digest1[i] & 0xFf;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                pwd.append(0);
            }
            pwd.append(hv);
        }
        return pwd.toString();
    }

    /**
     * 获取头部信息
     * @param request
     * @return
     */
    private Map<String, Object> getHeads(HttpServletRequest request){
        Map<String, Object> stringObjectHashMap = new HashMap<>();
        Enumeration<String> headers = request.getHeaderNames();
        while(headers.hasMoreElements()){
            String headName = (String)headers.nextElement();
            String headValue = request.getHeader(headName);
            stringObjectHashMap.put(headName,headValue);
        }
        return stringObjectHashMap;
    }

    /**
     * 判断日期是不是今天
     * @param date
     * @return    是返回true，不是返回false
     */
    public boolean isNow(Date date) {
        Date now = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        String nowDay = sf.format(now);
        String day = sf.format(date);
        return day.equals(nowDay);
    }

}
